#include "communicate.h"


Communicate::Communicate(const int port, const char *transitIp, const int transitPort, const char *peerMacAddr, const char *ownMacAddr)
	:UDP(port)
{
	if (ownMacAddr)
	{
		strcpy(_macAddr, ownMacAddr);
	}
	else
	{
		getLocalMacAddr(_macAddr);
	}
	
	char tmpTransitIp[32];
	if (transitIp[0] >= '0' && transitIp[0] <= '9')
	{
		strcpy(tmpTransitIp, transitIp);
	}
	else
	{
		getIpFromDomainName(tmpTransitIp, transitIp);
	}

	_transitNetAddr.sin_family = AF_INET;
	_transitNetAddr.sin_addr.s_addr = inet_addr(tmpTransitIp);
	_transitNetAddr.sin_port = htons(transitPort);
	strcpy(_peerMacAddr, peerMacAddr);
	std::cout << "own mac addr is " << _macAddr << std::endl;
	std::cout << "peer mac addr is " << _peerMacAddr << std::endl;
}

Communicate::~Communicate()
{

}

void Communicate::loginTransit()
{
	udpSendPackageData[0] = (unsigned char)eLoginCmd;
	memcpy(&udpSendPackageData[1], _macAddr, CPU_ID_SIZE);
	int packageSize = 1 + CPU_ID_SIZE;
	udpSendPackageData[packageSize] = 0;
	sendUdpPackage(udpSendPackageData, packageSize, listenSock, &_transitNetAddr);
	std::cout << "send login package to " << inet_ntoa(_transitNetAddr.sin_addr) << ":" << ntohs(_transitNetAddr.sin_port) << std::endl;
	std::cout << (int)(udpSendPackageData[0]) << "," << (char *)(udpSendPackageData + 1) << std::endl;
}

void Communicate::getPeerNetAddr()
{
	udpSendPackageData[0] = (unsigned char)eGetPeerNetAddrCmd;
	memcpy(&udpSendPackageData[1], _peerMacAddr, CPU_ID_SIZE);
	int packageSize = 1 + CPU_ID_SIZE;
	sendUdpPackage(udpSendPackageData, packageSize, listenSock, &_transitNetAddr);
}

void Communicate::penetrate()
{
	udpSendPackageData[0] = (unsigned char)ePenetrateCmd;
	int packageSize = 1;
	sendUdpPackage(udpSendPackageData, packageSize, listenSock, &_peerNetAddr);
}

void Communicate::sendNormal()
{
	udpSendPackageData[0] = (unsigned char)eNormalCmd;
	udpSendPackageData[1] = 9;
	udpSendPackageData[2] = 9;
	udpSendPackageData[3] = 5;
	int packageSize = 4;
	sendUdpPackage(udpSendPackageData, packageSize, listenSock, &_peerNetAddr);
}


int Communicate::dealPackage(const unsigned char *package, const int packageSize, const struct sockaddr_in *rNetAddr)
{
	ProtoCmd cmd = (ProtoCmd)package[0];
	switch (cmd)
	{
	case eLoginCmd:
		clientLoginRep(&package[1], packageSize - 1, rNetAddr);
		break;
	case eGetPeerNetAddrCmd:
		clientGetPeerNetAddrRep(&package[1], packageSize - 1, rNetAddr);
		break;
	case ePenetrateCmd:
		std::cout << "get ePenetrateCmd package ! netAddr is " << inet_ntoa(rNetAddr->sin_addr) << ":" << ntohs(rNetAddr->sin_port) << std::endl;
		break;
	case eNormalCmd:
		sendNormalRep(&package[1], packageSize - 1, rNetAddr);
		break;
	default:
		std::cout << "unknow cmd ! cmd = " << cmd << std::endl;
		break;
	}

	return 0;
}

int Communicate::clientLoginRep(const unsigned char *data, const int dataSize, const struct sockaddr_in *rNetAddr)
{
	if (dataSize != 1)
	{
		std::cout << "clientLoginRep dataSize fail ! dataSize = " << dataSize << std::endl;
	}

	std::cout << __FUNCTION__ << " result is " << (int)data[0] << std::endl;
	return 0;
}

int Communicate::clientGetPeerNetAddrRep(const unsigned char *data, const int dataSize, const struct sockaddr_in *rNetAddr)
{
	unsigned char result = data[0];
	if (data[0] > 0)
	{
		std::cout << "clientGetPeerNetAddrRep fail ! result = " << result << std::endl;
		return -1;
	}

	if (dataSize -1 != sizeof(struct sockaddr_in))
	{
		std::cout << "clientGetPeerNetAddrRep dataSize fail ! dataSize = " << dataSize << std::endl;
		return -2;
	}

	memcpy(&_peerNetAddr, &data[1], sizeof(struct sockaddr_in));
	std::cout << "get peer NAT is " << inet_ntoa(_peerNetAddr.sin_addr) << ":" << ntohs(_peerNetAddr.sin_port) << std::endl;
	return 0;
}

int Communicate::sendNormalRep(const unsigned char *data, const int dataSize, const struct sockaddr_in *rNetAddr)
{
	std::cout << "recv normal data from " << inet_ntoa(rNetAddr->sin_addr) << ":" << ntohs(rNetAddr->sin_port) << std::endl;
	for (int i = 0; i < dataSize; i ++)
	{
		std::cout << data[i] << " ";
	}
	std::cout << std::endl;

	return 0;
}
